import { Component, OnDestroy, OnInit } from '@angular/core';
import { NzFormatEmitEvent, NzTreeNodeOptions } from 'ng-zorro-antd';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { EzForm, EzFormComponent } from '../ez-form';
import { EzFormControlComponent } from '../ez-form-control';
import { EzFormGroup, EzFormGroupComponent } from '../ez-form-group';
import { EzFormItemComponent } from '../ez-form-item';
import { EzTreeSelect } from './ez-tree-select';
import { EzTreeSelectConfiguration, EzTreeSelectOptions } from './ez-tree-select.configuration';

@Component({
  selector: 'ez-tree-select',
  templateUrl: './ez-tree-select.component.html',
  styleUrls: ['./ez-tree-select.component.less'],
  providers: [{ provide: EzFormControlComponent, useExisting: EzTreeSelectComponent }],
})
export class EzTreeSelectComponent extends EzFormControlComponent<EzTreeSelectConfiguration, any>
  implements EzTreeSelect, OnInit, OnDestroy {
  constructor(
    protected ezForm: EzFormComponent,
    protected ezFormGroup: EzFormGroupComponent,
    protected ezFormItem: EzFormItemComponent
  ) {
    super(ezForm, ezFormGroup, ezFormItem);
  }

  defaultMaxTagCount = Infinity;

  nodes: NzTreeNodeOptions[] = [];

  ngOnInit(): void {
    super.ngOnInit();
    if (!this.isAsyncLoading()) {
      this.nodes = this.convertOptions(this.ezFormControlConfiguration.options as EzTreeSelectOptions[]);
    } else {
      this.loadNode(null).then(data => {
        this.nodes = data;
      });
    }
  }

  ngOnDestroy(): void {
    super.ngOnDestroy();
  }

  checkConfiguration(configuration: EzTreeSelectConfiguration): void {}

  onExpandChange(e: NzFormatEmitEvent): void {
    if (this.isAsyncLoading()) {
      const node = e.node;
      if (node && node.getChildren().length === 0 && node.isExpanded) {
        this.loadNode(node.origin.origin as EzTreeSelectOptions).then(data => {
          node.addChildren(data);
        });
      }
    }
  }

  loadNode(parent: EzTreeSelectOptions): Promise<NzTreeNodeOptions[]> {
    return (this.ezFormControlConfiguration.options as (
      parent: any,
      control: EzTreeSelect,
      group: EzFormGroup,
      form: EzForm
    ) => Observable<EzTreeSelectOptions[]>)(parent, this, this.ezFormGroup, this.ezForm)
      .pipe(map(options => this.convertOptions(options)))
      .toPromise();
  }

  private convertOptions(optionsArray: EzTreeSelectOptions[] = []): NzTreeNodeOptions[] {
    const results: NzTreeNodeOptions[] = [];
    optionsArray.forEach(op => {
      results.push({
        key: op.key || op.value,
        title: op.label,
        isLeaf: op.isLeaf,
        children: op.children ? this.convertOptions(op.children) : null,
        disabled: op.disabled,
        origin: op,
      });
    });
    return results;
  }

  isAsyncLoading(): boolean {
    return this.ezFormControlConfiguration.options instanceof Function;
  }
}
